using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Windows;
using System.Windows.Threading;
using NUnit.Framework;
using SCSFContrib.CompositeUI.WPF;

namespace SCSFContrib.CompositeUI.WPF.UnitTest
{
	[TestFixture]
	public sealed class ApplicationShellApplicationTest : UnitTest
	{
		private ApplicationShellApplication<TestableRootWorkItem, TestableApplication> _applicationShellApplication;

		protected override void SetUpCore()
		{
			base.SetUpCore();
			_applicationShellApplication = Mocks.PartialMock<ApplicationShellApplication<TestableRootWorkItem, TestableApplication>>();
			Mocks.ReplayAll();
		}

		[Test]
		public void AfterShellCreated_ShouldInitializeApplication()
		{
			ExecuteInSeparateAppDomain("AfterShellCreated_ShouldInitializeApplication_DoWork");
		}

		private void AfterShellCreated_ShouldInitializeApplication_DoWork()
		{
			ManualResetEvent synchronizationContextSet = new ManualResetEvent(false);
			SynchronizationContext synchronizationContext = null;

			//start up application on a separate thread
			Thread thread = CreateSTAThread(delegate
			{
				SynchronizationContext.SetSynchronizationContext(new DispatcherSynchronizationContext());
				synchronizationContext = SynchronizationContext.Current;
				synchronizationContextSet.Set();
				_applicationShellApplication.Run();
			});

			thread.Start();

			synchronizationContextSet.WaitOne();
			Application application = null;

			while (application == null)
			{
				Thread.SpinWait(100);

				synchronizationContext.Send(delegate
				{
					application = Application.Current;
				}, null);
			}

			synchronizationContext.Send(delegate
			{
				TestableApplication testableApplication = GetPrivateMemberValue<TestableApplication>(_applicationShellApplication, "Shell");
				Assert.IsTrue(testableApplication.Initialized);
				Application.Current.Shutdown();
			}, null);
		}

		[Test]
		public void Start_ShouldRunApplication()
		{
			ExecuteInSeparateAppDomain("Start_ShouldRunApplication_DoWork");
		}

		private void Start_ShouldRunApplication_DoWork()
		{
			ManualResetEvent synchronizationContextSet = new ManualResetEvent(false);
			SynchronizationContext synchronizationContext = null;

			//start up application on a separate thread
			Thread thread = CreateSTAThread(delegate
			{
				SynchronizationContext.SetSynchronizationContext(new DispatcherSynchronizationContext());
				synchronizationContext = SynchronizationContext.Current;
				synchronizationContextSet.Set();
				_applicationShellApplication.Run();
			});

			thread.Start();

			synchronizationContextSet.WaitOne();
			Application application = null;

			while (application == null)
			{
				Thread.SpinWait(100);

				synchronizationContext.Send(delegate
				{
					application = Application.Current;
				}, null);
			}

			synchronizationContext.Send(delegate
			{
				Application.Current.Shutdown();
			}, null);
		}

		#region Supporting Types

		public class TestableApplication : Application, IInitializeApplication
		{
			public bool Initialized;

			public void InitializeComponent()
			{
				Initialized = true;
			}
		}

		#endregion
	}
}
